#include <QStringList>
#include <QDebug>
#include <QProcess>
#include <QApplication>
#include <QFile>
#include <QTextStream>
#include <QSysInfo>

#include <cstdlib>

#include "settings.h"
#include "defines.h"
#include "symbiandefines.h"
#include "symbianprocessrunner.h"

SymbianProcessRunner::SymbianProcessRunner(SymbianQtProjectGenerator &generator)
    : m_process(0)
    , m_generator(generator)
    , m_errorWordInLogMsg(false)
{
}

SymbianProcessRunner::~SymbianProcessRunner()
{
    delete m_process;
}


void SymbianProcessRunner::runApp(GeneratorPhase &generatorAction,
                                  const QStringList &params)
{
    m_generatorAction = generatorAction;
    m_errorWordInLogMsg = false;

    delete m_process;
    m_process = 0;
    m_process = new QProcess( this );
    m_process->setReadChannelMode(QProcess::MergedChannels);

    if (m_generatorAction == QMAKE_APP ||
        m_generatorAction == MAKE_APP  ||
        m_generatorAction == MAKESIS_APP)
    {
        m_process->setWorkingDirectory(m_generator.generatorData().fwDirectory());
        switch (m_generatorAction.m_phase)
        {
        case QMAKE_APP:
            runQMake();
            break;
        case MAKE_APP:
            runMake();
            break;
        case MAKESIS_APP:
            runMakeSis();
            break;
        default:
            break;
        }
    }
    else if (m_generatorAction == UNZIP_WIDGET)
    {
        runUnzip(params);
    }
}


bool SymbianProcessRunner::errorWordInLogMessage()
{
    return m_errorWordInLogMsg;
}


void SymbianProcessRunner::readProcessStdout()
{
    QString msg(((QProcess*) sender())->readAllStandardOutput());
    if (msg.toLower().contains("error "))
        m_errorWordInLogMsg = true;

    m_generator.outputView().printOutput(msg);
}


void SymbianProcessRunner::startProcess(const QString &command, const QStringList &arguments)
{
    m_generator.outputView().printOutput("command: " + command);
    m_process->start(command, arguments);

    if (m_generator.outputView().cliOutput())
        m_process->waitForFinished(-1);
}


void SymbianProcessRunner::runQMake()
{
    m_generator.outputView().printOutput("\n");
    m_generator.outputView().printOutput("*********************************");
    m_generator.outputView().printOutput("*  Running qmake for hybrid app  ");
    m_generator.outputView().printOutput("*********************************");
    m_generator.outputView().printOutput(m_generator.generatorData().projectDirectory());

    connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readProcessStdout()));
    connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), &m_generator, SLOT(qmakeFinished(int, QProcess::ExitStatus)));

    m_process->setWorkingDirectory(m_generator.generatorData().projectDirectory());
    QString
        cl(getFullCmdLine("qmake"));
    m_process->start(cl);
    if (m_generator.outputView().cliOutput())
        m_process->waitForFinished(-1);
}


void SymbianProcessRunner::runMake()
{
    m_generator.outputView().printOutput("\n");
    m_generator.outputView().printOutput("*********************************");
    m_generator.outputView().printOutput("*  Running make for hybrid app   ");
    m_generator.outputView().printOutput("*********************************");

    connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readProcessStdout()));
    connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), &m_generator, SLOT(makeFinished(int, QProcess::ExitStatus)));

    m_process->setWorkingDirectory(m_generator.generatorData().projectDirectory());
    QString
        cl(getFullCmdLine("make release-gcce"));
    m_process->start(cl);
    if (m_generator.outputView().cliOutput())
        m_process->waitForFinished(-1);
}

void SymbianProcessRunner::runMakeSis()
{
    m_generator.outputView().printOutput("\n");
    m_generator.outputView().printOutput("*********************************");
    m_generator.outputView().printOutput("*  Running makesis for hybrid app");
    m_generator.outputView().printOutput("*********************************");

    connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readProcessStdout()));
    connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), &m_generator, SLOT(makesisFinished(int, QProcess::ExitStatus)));

    // TODO here could also be defined the smart installer generation
    m_process->setWorkingDirectory(m_generator.generatorData().projectDirectory());
    QString
        cl(getFullCmdLine("make sis"));
    m_process->start(cl);
    if (m_generator.outputView().cliOutput())
        m_process->waitForFinished(-1);
}

void SymbianProcessRunner::runUnzip(const QStringList &params)
{
    m_generator.outputView().printOutput("\n");
    m_generator.outputView().printOutput("*********************************");
    m_generator.outputView().printOutput("*  Unzipping widget " + params[0]);
    m_generator.outputView().printOutput("*********************************");

    connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readProcessStdout()));
    connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), &m_generator, SLOT(widgetFilesCopied(int, QProcess::ExitStatus)));

    QStringList arguments = (QStringList() << "-xo" << params[0] << "-d" << params[1]);
    startProcess(UNZIP_APP_NAME, arguments);
}


namespace
{
    QString GetSymbianSDKDefaultDevice()
    {
        QString
            rv;

        QProcess
            tmp;
        tmp.start("cmd /C devices");
        tmp.waitForFinished(-1);
        if (tmp.exitCode() == 0)
        {
            QString
                output = tmp.readAllStandardOutput();
            QStringList
                lines = output.split("\r\n", QString::SkipEmptyParts);
            foreach (QString line, lines)
            {
                if (line.contains("- default"))
                {
                    rv = line.mid(0,
                                  line.indexOf(" - "));
                    break;
                }
            }
        }
        else
        {
            // TODO report error?
        }

        return rv;
    }


    QString GetSymbianSDKDefaultDevicePath(const QString symbianDefaultDevice)
    {
        QString
            rv;

        QProcess
            tmp;
        QString
            clArg("cmd /C devices -info @%1");
        clArg = clArg.arg(symbianDefaultDevice);
        tmp.start(clArg);
        tmp.waitForFinished(-1);
        if (tmp.exitCode() == 0)
        {
            QString
                output = tmp.readAllStandardOutput();
            QStringList
                lines = output.split("\r\n", QString::SkipEmptyParts);
            foreach (QString line, lines)
            {
                if (line.contains("Root is "))
                {
                    rv = line.mid(QString("Root is ").length()); // TODO duplication of information
                    break;
                }
            }
        }
        else
        {
            // TODO report error?
        }

        return rv;
    }
}


QString SymbianProcessRunner::getFullCmdLine(const QString & partialCmdLine)
{
    bool
        fullSymbianSDK = Settings::get(Settings::FullS60SDK).toBool();

    QString
        fullCmdLine("%1 & %2");
    fullCmdLine = fullCmdLine.arg(Settings::get(Settings::QtEnvBatPath).toString(),
                                                partialCmdLine);
    QSysInfo::WinVersion
        winVersion = QSysInfo::WindowsVersion;
    if (fullSymbianSDK
        && (winVersion == QSysInfo::WV_VISTA
            || winVersion == QSysInfo::WV_WINDOWS7))
    {
        QString
            defaultDevice = GetSymbianSDKDefaultDevice();
        QString
            defaultDevicePath = GetSymbianSDKDefaultDevicePath(defaultDevice);
        QString
            vistaPatchPath("%1\\Plugins\\vistapatch\\Env.bat");
        vistaPatchPath = vistaPatchPath.arg(defaultDevicePath);

        if (QFile::exists(vistaPatchPath))
        {
            fullCmdLine = vistaPatchPath + " & " + fullCmdLine;
        }
    }

    QString
        rv("cmd /C \"%1\"");

    rv = rv.arg(fullCmdLine);

    return rv;
}
